<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------

namespace randy\queue;

use Exception;
use randy\queue\job\Amqp;
use think\facade\Hook;
use think\facade\Log;
use think\Queue;

class Worker {


	/**
	 * Process 处理任务
	 *
	 * @param Amqp $job
	 * @param int  $maxTries
	 * @param int  $delay
	 *
	 * @return bool
	 * @throws Exception
	 */
	public function process(Amqp $job, $maxTries = 0, $delay = 0) {
		$job->amqp->setJobStatus($job->msg_id(), 0);
		//超过最大重试次数 则触发失败通知事件
		if ($maxTries > 0 && $job->attempts() > $maxTries) {
			$job->amqp->setJobStatus($job->msg_id(), -1);
			return $this->logFailedJob($job);
		}

		try {
			$res = $job->fire();
			//任务执行成功 进行本地ack确认
			if ($res !== false) {
				$job->ack($job);
				$job->amqp->setJobStatus($job->msg_id(), 1);
			}
		} catch (Exception $e) {
			//记录异常信息
			$msg = '队列执行异常 : ' . PHP_EOL;
			$msg .= '队列 : ' . $job->getQueue() . PHP_EOL;
			$msg .= '脚本名称 : ' . $job->getJobName() . PHP_EOL;
			$msg .= '脚本 : ' . $job->getJob() . PHP_EOL;
			$msg .= '执行数据 : ' . json_encode($job->getData(), JSON_UNESCAPED_UNICODE) . PHP_EOL;
			$msg .= '异常信息 : ' . $e->getMessage() . PHP_EOL;
			$msg .= '异常文件 : ' . $e->getFile() . PHP_EOL;
			$msg .= '异常行号 : ' . $e->getLine() . PHP_EOL;
			Log::error($msg);
			if (!$job->isDeleted()) {
				$job->release($delay);
			}
			$job->amqp->setJobStatus($job->msg_id(), -1);
		}
		return true;
	}

	/**
	 * Log a failed job into storage.
	 *
	 * @param Job $job
	 *
	 * @return true
	 */
	protected function logFailedJob(Job $job) {
		if (!$job->isDeleted()) {
			try {
				$job->delete();
				$job->failed();
			} finally {
				Hook::listen('queue_failed', $job);
			}
		}
		return true;

	}

	/**
	 * Sleep the script for a given number of seconds.
	 *
	 * @param int $seconds
	 *
	 * @return void
	 */
	public function sleep($seconds) {
		sleep($seconds);
	}

}
